package com.pear.core.ctl;

import java.math.BigDecimal;
import java.math.BigInteger;

/**
 * 类<code>NumberTools</code>提供了数字相关的快捷功能。
 *
 * @author 顾晓健
 * @version %I%, %G%
 * @since 1.0
 */
public class NumberTools {

    /**
     * <p>将字符串转为整数，如果转换失败返回整数0。</p>
     * <pre><font color=green>
     * NumberTools.toInt(null) = 0
     * NumberTools.toInt("")   = 0
     * NumberTools.toInt("1")  = 1
     * </font></pre>
     *
     * @param str 待转字符串
     * @return 字符串对应的整数，若失败则返回整数0
     */
    public static int toInt(String str) {
        return toInt(str, 0);
    }

    /**
     * <p>将字符串转为整数，如果转换失败返回指定的默认值。</p>
     * <pre><font color=green>
     * NumberTools.toInt(null, 1) = 1
     * NumberTools.toInt("", 1)   = 1
     * NumberTools.toInt("1", 0)  = 1
     * </font></pre>
     *
     * @param str          待转字符串
     * @param defaultValue 默认值
     * @return 字符串对应的整数，若失败则返回默认值
     */
    public static int toInt(String str, int defaultValue) {
        if (str == null) {
            return defaultValue;
        }

        try {
            return Integer.parseInt(str);
        } catch (NumberFormatException nfe) {
            return defaultValue;
        }
    }

    /**
     * <p>将字符串转为长整数，如果转换失败返回0。</p>
     * <pre><font color=green>
     * NumberTools.toLong(null) = 0L
     * NumberTools.toLong("")   = 0L
     * NumberTools.toLong("1")  = 1L
     * </font></pre>
     *
     * @param str 待转字符串
     * @return 字符串对应的长整数，若失败则返回0
     */
    public static long toLong(String str) {
        return toLong(str, 0L);
    }

    /**
     * <p>将字符串转为长整数，如果转换失败返回指定的默认值。</p>
     * <pre><font color=green>
     * NumberTools.toLong(null, 1L) = 1L
     * NumberTools.toLong("", 1L)   = 1L
     * NumberTools.toLong("1", 0L)  = 1L
     * </font></pre>
     *
     * @param str          待转字符串
     * @param defaultValue 默认值
     * @return 字符串对应的长整数，若失败则返回默认值
     */
    public static long toLong(String str, long defaultValue) {
        if (str == null) {
            return defaultValue;
        }

        try {
            return Long.parseLong(str);
        } catch (NumberFormatException nfe) {
            return defaultValue;
        }
    }

    /**
     * <p>将字符串转为浮点数，如果转换失败返回0.0f。</p>
     * <pre><font color=green>
     * NumberTools.toFloat(null)   = 0.0f
     * NumberTools.toFloat("")     = 0.0f
     * NumberTools.toFloat("1.5")  = 1.5f
     * </font></pre>
     *
     * @param str 待转字符串
     * @return 字符串对应的浮点数，若失败则返回0.0f
     */
    public static float toFloat(String str) {
        return toFloat(str, 0.0f);
    }

    /**
     * <p>将字符串转为浮点数，如果转换失败返回指定的默认值。</p>
     * <pre><font color=green>
     * NumberTools.toFloat(null, 1.1f)   = 1.0f
     * NumberTools.toFloat("", 1.1f)     = 1.1f
     * NumberTools.toFloat("1.5", 0.0f)  = 1.5f
     * </font></pre>
     *
     * @param str          待转字符串
     * @param defaultValue 默认值
     * @return 字符串对应的浮点数，若失败则返回默认值
     */
    public static float toFloat(String str, float defaultValue) {
        if (str == null) {
            return defaultValue;
        }

        try {
            return Float.parseFloat(str);
        } catch (NumberFormatException nfe) {
            return defaultValue;
        }
    }

    /**
     * <p>将字符串转为双精度浮点数，如果转换失败返回0.0d。</p>
     * <pre><font color=green>
     * NumberTools.toDouble(null)   = 0.0d
     * NumberTools.toDouble("")     = 0.0d
     * NumberTools.toDouble("1.5")  = 1.5d
     * </font></pre>
     *
     * @param str 待转字符串
     * @return 字符串对应的浮点数，若失败则返回0.0d
     */
    public static double toDouble(String str) {
        return toDouble(str, 0.0d);
    }

    /**
     * <p>将字符串转为双精度浮点数，如果转换失败返回指定的默认值。</p>
     * <pre><font color=green>
     * NumberTools.toDouble(null, 1.1d)   = 1.1d
     * NumberTools.toDouble("", 1.1d)     = 1.1d
     * NumberTools.toDouble("1.5", 0.0d)  = 1.5d
     * </font></pre>
     *
     * @param str          待转字符串
     * @param defaultValue 默认值
     * @return 字符串对应的浮点数，若失败则返回默认值
     */
    public static double toDouble(String str, double defaultValue) {
        if (str == null) {
            return defaultValue;
        }

        try {
            return Double.parseDouble(str);
        } catch (NumberFormatException nfe) {
            return defaultValue;
        }
    }

    /**
     * <p>将字符串转为字节，如果转换失败返回0。</p>
     * <pre><font color=green>
     * NumberTools.toByte(null) = 0
     * NumberTools.toByte("")   = 0
     * NumberTools.toByte("1")  = 1
     * </font></pre>
     *
     * @param str 待转字符串
     * @return 字符串对应的浮点数，若失败则返回0
     */
    public static byte toByte(String str) {
        return toByte(str, (byte) 0);
    }

    /**
     * <p>将字符串转为字节，如果转换失败返回指定的默认值。</p>
     * <pre><font color=green>
     * NumberTools.toByte(null, 1) = 1
     * NumberTools.toByte("", 1)   = 1
     * NumberTools.toByte("1", 0)  = 1
     * </font></pre>
     *
     * @param str          待转字符串
     * @param defaultValue 默认值
     * @return 字符串对应的字节，若失败则返回0
     */
    public static byte toByte(String str, byte defaultValue) {
        if (str == null) {
            return defaultValue;
        }

        try {
            return Byte.parseByte(str);
        } catch (NumberFormatException nfe) {
            return defaultValue;
        }
    }

    /**
     * <p>将字符串转为短整数，如果转换失败返回0。</p>
     * <pre><font color=green>
     * NumberTools.toShort(null) = 0
     * NumberTools.toShort("")   = 0
     * NumberTools.toShort("1")  = 1
     * </font></pre>
     *
     * @param str 待转字符串
     * @return 字符串对应的字节，若失败则返回0
     */
    public static short toShort(String str) {
        return toShort(str, (short) 0);
    }

    /**
     * <p>将字符串转为短整数，如果转换失败返回指定的默认值。</p>
     * <pre><font color=green>
     * NumberTools.toShort(null, 1) = 1
     * NumberTools.toShort("", 1)   = 1
     * NumberTools.toShort("1", 0)  = 1
     * </font></pre>
     *
     * @param str          待转字符串
     * @param defaultValue 默认值
     * @return 字符串对应的字节，若失败则返回默认值
     */
    public static short toShort(String str, short defaultValue) {
        if (str == null) {
            return defaultValue;
        }

        try {
            return Short.parseShort(str);
        } catch (NumberFormatException nfe) {
            return defaultValue;
        }
    }

    /**
     * <p>将字符串转为Float。</p>
     *
     * @param str 待转字符串
     * @return 待转字符串对应的Float对象，如果待转字符串为Null，则返回Null
     */
    public static Float createFloat(String str) {
        if (str == null) {
            return null;
        }

        return Float.valueOf(str);
    }

    /**
     * <p>将字符串转为Double。</p>
     *
     * @param str 待转字符串
     * @return 待转字符串对应的Double对象，如果待转字符串为Null，则返回Null
     */
    public static Double createDouble(String str) {
        if (str == null) {
            return null;
        }

        return Double.valueOf(str);
    }

    /**
     * <p>将字符串转为Integer。</p>
     *
     * @param str 待转字符串
     * @return 待转字符串对应的Integer对象，如果待转字符串为Null，则返回Null
     */
    public static Integer createInteger(String str) {
        if (str == null) {
            return null;
        }

        return Integer.decode(str);
    }

    /**
     * <p>将字符串转为Long。</p>
     *
     * @param str 待转字符串
     * @return 待转字符串对应的Long对象，如果待转字符串为Null，则返回Null
     */
    public static Long createLong(String str) {
        if (str == null) {
            return null;
        }

        return Long.decode(str);
    }

    /**
     * <p>将字符串转为BigInteger。</p>
     *
     * @param str 待转字符串
     * @return 待转字符串对应的BigInteger对象，如果待转字符串为Null，则返回Null
     */
    public static BigInteger createBigInteger(String str) {
        if (str == null) {
            return null;
        }

        return new BigInteger(str);
    }

    /**
     * <p>将字符串转为BigDecimal。</p>
     *
     * @param str 待转字符串
     * @return 待转字符串对应的BigDecimal对象，如果待转字符串为Null，则返回Null
     */
    public static BigDecimal createBigDecimal(String str) {
        if (str == null) {
            return null;
        }

        if (StringTools.isBlank(str)) {
            throw new NumberFormatException("A blank string is not a valid number");
        }

        return new BigDecimal(str);
    }

    /**
     * <p>返回数组中最小的长整数。</p>
     *
     * @param array 待寻找数组
     * @return 最小的长整数
     */
    public static long min(long[] array) {
        if (array == null) {
            throw new IllegalArgumentException("The Array must not be null");
        } else if (array.length == 0) {
            throw new IllegalArgumentException("Array cannot be empty.");
        }

        long min = array[0];
        for (int i = 1; i < array.length; i++) {
            if (array[i] < min) {
                min = array[i];
            }
        }

        return min;
    }

    /**
     * <p>返回数组中最小的整数。</p>
     *
     * @param array 待寻找数组
     * @return 最小的整数
     */
    public static int min(int[] array) {
        if (array == null) {
            throw new IllegalArgumentException("The Array must not be null");
        } else if (array.length == 0) {
            throw new IllegalArgumentException("Array cannot be empty.");
        }

        int min = array[0];
        for (int j = 1; j < array.length; j++) {
            if (array[j] < min) {
                min = array[j];
            }
        }

        return min;
    }

    /**
     * <p>返回数组中最小的短整数。</p>
     *
     * @param array 待寻找数组
     * @return 最小的短整数
     */
    public static short min(short[] array) {
        if (array == null) {
            throw new IllegalArgumentException("The Array must not be null");
        } else if (array.length == 0) {
            throw new IllegalArgumentException("Array cannot be empty.");
        }

        short min = array[0];
        for (int i = 1; i < array.length; i++) {
            if (array[i] < min) {
                min = array[i];
            }
        }

        return min;
    }

    /**
     * <p>返回数组中最小的字节。</p>
     *
     * @param array 待寻找数组
     * @return 最小的字节
     */
    public static byte min(byte[] array) {
        if (array == null) {
            throw new IllegalArgumentException("The Array must not be null");
        } else if (array.length == 0) {
            throw new IllegalArgumentException("Array cannot be empty.");
        }

        byte min = array[0];
        for (int i = 1; i < array.length; i++) {
            if (array[i] < min) {
                min = array[i];
            }
        }

        return min;
    }

    /**
     * <p>返回数组中最小的双精度浮点数。</p>
     *
     * @param array 待寻找数组
     * @return 最小的双精度浮点数
     */
    public static double min(double[] array) {
        if (array == null) {
            throw new IllegalArgumentException("The Array must not be null");
        } else if (array.length == 0) {
            throw new IllegalArgumentException("Array cannot be empty.");
        }

        double min = array[0];
        for (int i = 1; i < array.length; i++) {
            if (Double.isNaN(array[i])) {
                return Double.NaN;
            }
            if (array[i] < min) {
                min = array[i];
            }
        }

        return min;
    }

    /**
     * <p>返回数组中最小的浮点数。</p>
     *
     * @param array 待寻找数组
     * @return 最小的浮点数
     */
    public static float min(float[] array) {
        if (array == null) {
            throw new IllegalArgumentException("The Array must not be null");
        } else if (array.length == 0) {
            throw new IllegalArgumentException("Array cannot be empty.");
        }

        float min = array[0];
        for (int i = 1; i < array.length; i++) {
            if (Float.isNaN(array[i])) {
                return Float.NaN;
            }
            if (array[i] < min) {
                min = array[i];
            }
        }

        return min;
    }

    /**
     * <p>返回数组中最大的长整数。</p>
     *
     * @param array 待寻找数组
     * @return 最大的长整数
     */
    public static long max(long[] array) {
        if (array == null) {
            throw new IllegalArgumentException("The Array must not be null");
        } else if (array.length == 0) {
            throw new IllegalArgumentException("Array cannot be empty.");
        }

        long max = array[0];
        for (int j = 1; j < array.length; j++) {
            if (array[j] > max) {
                max = array[j];
            }
        }

        return max;
    }

    /**
     * <p>返回数组中最大的整数。</p>
     *
     * @param array 待寻找数组
     * @return 最大的整数
     */
    public static int max(int[] array) {
        if (array == null) {
            throw new IllegalArgumentException("The Array must not be null");
        } else if (array.length == 0) {
            throw new IllegalArgumentException("Array cannot be empty.");
        }

        int max = array[0];
        for (int j = 1; j < array.length; j++) {
            if (array[j] > max) {
                max = array[j];
            }
        }

        return max;
    }

    /**
     * <p>返回数组中最大的短整数。</p>
     *
     * @param array 待寻找数组
     * @return 最大的短整数
     */
    public static short max(short[] array) {
        if (array == null) {
            throw new IllegalArgumentException("The Array must not be null");
        } else if (array.length == 0) {
            throw new IllegalArgumentException("Array cannot be empty.");
        }

        short max = array[0];
        for (int i = 1; i < array.length; i++) {
            if (array[i] > max) {
                max = array[i];
            }
        }

        return max;
    }

    /**
     * <p>返回数组中最大的字节。</p>
     *
     * @param array 待寻找数组
     * @return 最大的字节
     */
    public static byte max(byte[] array) {
        if (array == null) {
            throw new IllegalArgumentException("The Array must not be null");
        } else if (array.length == 0) {
            throw new IllegalArgumentException("Array cannot be empty.");
        }

        byte max = array[0];
        for (int i = 1; i < array.length; i++) {
            if (array[i] > max) {
                max = array[i];
            }
        }

        return max;
    }

    /**
     * <p>返回数组中最大的双精度浮点数。</p>
     *
     * @param array 待寻找数组
     * @return 最大的双精度浮点数
     */
    public static double max(double[] array) {
        if (array == null) {
            throw new IllegalArgumentException("The Array must not be null");
        } else if (array.length == 0) {
            throw new IllegalArgumentException("Array cannot be empty.");
        }

        double max = array[0];
        for (int j = 1; j < array.length; j++) {
            if (Double.isNaN(array[j])) {
                return Double.NaN;
            }
            if (array[j] > max) {
                max = array[j];
            }
        }

        return max;
    }

    /**
     * <p>返回数组中最大的浮点数。</p>
     *
     * @param array 待寻找数组
     * @return 最大的浮点数
     */
    public static float max(float[] array) {
        if (array == null) {
            throw new IllegalArgumentException("The Array must not be null");
        } else if (array.length == 0) {
            throw new IllegalArgumentException("Array cannot be empty.");
        }

        float max = array[0];
        for (int j = 1; j < array.length; j++) {
            if (Float.isNaN(array[j])) {
                return Float.NaN;
            }
            if (array[j] > max) {
                max = array[j];
            }
        }

        return max;
    }

    /**
     * <p>返回3个长整数中的最小的。</p>
     *
     * @param a 长整数1
     * @param b 长整数2
     * @param c 长整数3
     * @return 最小的长整数
     */
    public static long min(long a, long b, long c) {
        if (b < a) {
            a = b;
        }

        if (c < a) {
            a = c;
        }

        return a;
    }

    /**
     * <p>返回3个整数中的最小的。</p>
     *
     * @param a 整数1
     * @param b 整数2
     * @param c 整数3
     * @return 最小的整数
     */
    public static int min(int a, int b, int c) {
        if (b < a) {
            a = b;
        }

        if (c < a) {
            a = c;
        }

        return a;
    }

    /**
     * <p>返回3个短整数中的最小的。</p>
     *
     * @param a 短整数1
     * @param b 短整数2
     * @param c 短整数3
     * @return 最小的短整数
     */
    public static short min(short a, short b, short c) {
        if (b < a) {
            a = b;
        }

        if (c < a) {
            a = c;
        }

        return a;
    }

    /**
     * <p>返回3个字节中的最小的。</p>
     *
     * @param a 字节1
     * @param b 字节2
     * @param c 字节3
     * @return 最小的字节
     */
    public static byte min(byte a, byte b, byte c) {
        if (b < a) {
            a = b;
        }

        if (c < a) {
            a = c;
        }

        return a;
    }

    /**
     * <p>返回3个双精度浮点数中的最小的。</p>
     *
     * @param a 双精度浮点数1
     * @param b 双精度浮点数2
     * @param c 双精度浮点数3
     * @return 最小的双精度浮点数
     */
    public static double min(double a, double b, double c) {
        return Math.min(Math.min(a, b), c);
    }

    /**
     * <p>返回3个浮点数中的最小的。</p>
     *
     * @param a 浮点数1
     * @param b 浮点数2
     * @param c 浮点数3
     * @return 最小的浮点数
     */
    public static float min(float a, float b, float c) {
        return Math.min(Math.min(a, b), c);
    }

    /**
     * <p>返回3个长整数中的最大的。</p>
     *
     * @param a 长整数1
     * @param b 长整数2
     * @param c 长整数3
     * @return 最大的长整数
     */
    public static long max(long a, long b, long c) {
        if (b > a) {
            a = b;
        }

        if (c > a) {
            a = c;
        }

        return a;
    }

    /**
     * <p>返回3个整数中的最大的。</p>
     *
     * @param a 整数1
     * @param b 整数2
     * @param c 整数3
     * @return 最大的整数
     */
    public static int max(int a, int b, int c) {
        if (b > a) {
            a = b;
        }

        if (c > a) {
            a = c;
        }

        return a;
    }

    /**
     * <p>返回3个短整数中的最大的。</p>
     *
     * @param a 短整数1
     * @param b 短整数2
     * @param c 短整数3
     * @return 最大的短整数
     */
    public static short max(short a, short b, short c) {
        if (b > a) {
            a = b;
        }

        if (c > a) {
            a = c;
        }

        return a;
    }

    /**
     * <p>返回3个字节中的最大的。</p>
     *
     * @param a 字节1
     * @param b 字节2
     * @param c 字节3
     * @return 最大的字节
     */
    public static byte max(byte a, byte b, byte c) {
        if (b > a) {
            a = b;
        }

        if (c > a) {
            a = c;
        }

        return a;
    }

    /**
     * <p>返回3个双精度浮点数中的最大的。</p>
     *
     * @param a 双精度浮点数1
     * @param b 双精度浮点数2
     * @param c 双精度浮点数3
     * @return 最大的双精度浮点数
     */
    public static double max(double a, double b, double c) {
        return Math.max(Math.max(a, b), c);
    }

    /**
     * <p>返回3个浮点数中的最大的。</p>
     *
     * @param a 浮点数1
     * @param b 浮点数2
     * @param c 浮点数3
     * @return 最大的浮点数
     */
    public static float max(float a, float b, float c) {
        return Math.max(Math.max(a, b), c);
    }

    /**
     * <p>判断字符串中是否只含有数字。</p>
     *
     * @param str 待判断字符串
     * @return 如果全部为数字，则返回{@code true}；否则返回{@code false}
     */
    public static boolean isDigits(String str) {
        if (StringTools.isEmpty(str)) {
            return false;
        }

        for (int i = 0; i < str.length(); i++) {
            if (!Character.isDigit(str.charAt(i))) {
                return false;
            }
        }

        return true;
    }

}
